﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Vit.Common
{
    public class ProviderManager
    {
        private static Dictionary<Type, List<IProvider>> providers = new Dictionary<Type, List<IProvider>>();
        private static object lockObj = new object();

        public static void Register<T>(T obj) where T : IProvider
        {
            Type type = typeof(T);
            obj.Registering();
            lock (lockObj)
            {
                if (providers.ContainsKey(type))
                {
                    if (providers[type] == null)
                        providers[type] = new List<IProvider>();
                    if (providers[type].Contains(obj) == false)
                        providers[type].Add(obj);
                }
                else
                {
                    List<IProvider> ps = new List<IProvider>();
                    ps.Add(obj);
                    providers.Add(type, ps);
                }
            }
            obj.Registered();
        }

        public static void RegisterSingleton<T>(T obj) where T : IProvider
        {
            Type type = typeof(T);
            obj.Registering();
            lock (lockObj)
            {
                if (providers.ContainsKey(type))
                {
                    if (providers[type] == null)
                        providers[type] = new List<IProvider>();
                    providers[type].Clear();
                    providers[type].Add(obj);
                }
                else
                {
                    List<IProvider> ps = new List<IProvider>();
                    ps.Add(obj);
                    providers.Add(type, ps);
                }
            }
            obj.Registered();
        }

        public static void Remove<T>(T obj) where T : IProvider
        {
            Type type = typeof(T);
            lock (lockObj)
            {
                if (providers.ContainsKey(type))
                {
                    if (providers[type] != null && providers[type].Contains(obj))
                        providers[type].Remove(obj);
                }
            }
        }

        public static void RemoveSingleton<T>() where T : IProvider
        {
            Type type = typeof(T);
            lock (lockObj)
            {
                if (providers.ContainsKey(type))
                {
                    if (providers[type] != null)
                        providers.Remove(type);
                }
            }
        }

        public static bool Contains<T>() where T : IProvider
        {
            Type type = typeof(T);
            return providers.ContainsKey(type) && providers[type] != null && providers[type].Count > 0;
        }

        public static bool ContainsSingleton<T>() where T : IProvider
        {
            Type type = typeof(T);
            return providers.ContainsKey(type) && providers[type] != null && providers[type].Count > 0;
        }

        public static List<T> Get<T>() where T : IProvider
        {
            Type type = typeof(T);
            if (Contains<T>())
                return providers[type].ConvertAll<T>(p => (T)p);
            return new List<T>();
        }

        public static T GetSingleton<T>() where T : IProvider
        {
            Type type = typeof(T);
            if (ContainsSingleton<T>())
                return (T)providers[type][0];
            return default(T);
        }

        public static void RunProviders<T>(Func<T, bool> action) where T : IProvider
        {
            Type type = typeof(T);
            if (providers.ContainsKey(type) && providers[type] != null)
            {
                bool lastActionResult = true;
                foreach (T provider in providers[type])
                {
                    if (lastActionResult)
                    {
                        provider.Executing();
                        lastActionResult = action(provider);
                        provider.Executed();
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        public static void RunSingletonProvider<T>(Func<T, bool> action) where T : IProvider
        {
            Type type = typeof(T);
            T provider = GetSingleton<T>();
            if (provider != null)
            {
                provider.Executing();
                action(provider);
                provider.Executed();
            }
        }
    }
}
